package com.mapforge.map.tilewriter;

import java.awt.Graphics2D;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import com.mapforge.map.Tile;
import com.mapforge.map.Tileset;
import com.mapforge.selection.Selection;
import com.mapforge.selection.TileSelection;

public class RandomTileWriter extends AbstractTileWriter {

	private long previousSeed;
	private Random seedGenerator;
	private Random tileGenerator;

	public RandomTileWriter() {
		super();
		seedGenerator = new Random();
		previousSeed = seedGenerator.nextLong();
		tileGenerator = new Random(previousSeed);
	}

	@Override
	public void previewWrite(Graphics2D g, TileSelection tileSelection,
			Selection destination) {
		tileGenerator.setSeed(previousSeed);
		Iterator<? extends Point> it = destination.iterator();
		Iterator<? extends Point> tileIT = tileSelection.iterator();
		Tileset tileset = getTileset();
		Point p;
		Tile tile;
		int tileWidth = tileset.getTileWidth();
		int tileHeight = tileset.getTileHeight();

		// store all tiles in input to a collection
		List<Tile> tileSelectionPnts = new ArrayList<Tile>();
		while (tileIT.hasNext()) {
			p = tileIT.next();
			tileSelectionPnts.add(tileset.getTileAt(p.x, p.y));
		}
		// while destination has points...
		while (it.hasNext()) {
			p = it.next();
			// render a randomly selected tile from input
			tile = tileSelectionPnts.get(tileGenerator
					.nextInt(tileSelectionPnts.size()));
			tile.render(g, p.x * tileWidth, p.y * tileHeight);
		}
	}

	public List<Tile> writeTiles(TileSelection input, Selection destination) {
		this.validateWriteState(input, destination);
		tileGenerator.setSeed(previousSeed);
		Iterator<? extends Point> it = destination.iterator();
		Iterator<? extends Point> tileIT = input.iterator();
		Point p;
		Tile tile;
		Tileset tileset = this.getTileset();
		// store all tiles in input to a collection
		List<Tile> tileSelectionPnts = new ArrayList<Tile>();
		while (tileIT.hasNext()) {
			p = tileIT.next();
			tileSelectionPnts.add(tileset.getTileAt(p.x, p.y));
		}

		while (it.hasNext()) {
			p = it.next();
			// render a randomly selected tile from input
			tile = tileSelectionPnts.get(tileGenerator
					.nextInt(tileSelectionPnts.size()));
			getTileLayer().setTile(p.x, p.y, tile);
		}
		return null;
	}

	/**
	 * Selects a new seed to use in randomly selecting tiles from input to write
	 * to destination.
	 * 
	 * @Override
	 */
	public void endWrite() {
		super.endWrite();
		previousSeed = seedGenerator.nextLong();
	}

	/**
	 * Randomly generates a new seed to use in randomly selecting tiles from
	 * input to write to destination.
	 * 
	 * @Override
	 */
	public void beginPreview() {
		super.beginPreview();
		previousSeed = seedGenerator.nextLong();
		tileGenerator.setSeed(previousSeed);
	}

	/**
	 * Set this pseudo-random number generator's seed to the last selected seed
	 * used in previewing this {@link TileWriter tile writer's} behavior.
	 * 
	 * @Override
	 */
	public void beginWrite() {
		super.beginWrite();
		tileGenerator.setSeed(previousSeed);
	}

}
